//<<<+++OPENSOURCE
//<<<+++OPENSOURCE_LICENSE
//<<<+++OPENSOURCE_BEGIN LIC==FOXIT||LIC==GOOGLE

/**
 * @addtogroup FXCRT
 * @{
 */

/**
 * @file
 * @brief Streams
 */

//<<<+++OPENSOURCE_MUST_BEGIN
#ifndef _FX_STREAM_H_
#define _FX_STREAM_H_

#ifndef _FX_MEMORY_H_
	#include "fx_memory.h"
#endif
//<<<+++OPENSOURCE_MUST_END

//*****************************************************************************
//* Folder access
//*****************************************************************************
/**
 * @brief	Open a folder for reading.
 * @param[in] path	path name of folder.
 * @return	NULL for error.
 */
void* FX_OpenFolder(FX_LPCSTR path);
void* FX_OpenFolder(FX_LPCWSTR path);

/**
 * @brief	Read next entry in the folder.
 * @param[in] handle	folder handle returned by FX_OpenFolder function.
 * @param[out] filename	receives file name when find a folder item.
 * @param[out] bFolder	indicates filename is a sub-folder or normal file.
 * @return	FALSE if reach end of folder.
 */
FX_BOOL FX_GetNextFile(void* handle, CFX_ByteString& filename, FX_BOOL& bFolder);
FX_BOOL FX_GetNextFile(void* handle, CFX_WideString& filename, FX_BOOL& bFolder);

/**
 * @brief	Close folder handle.
 * @param[in] handle	folder handle returned by FX_OpenFolder function.
 */
void FX_CloseFolder(void* handle);

/**
 * @brief	Get folder separator for the system. Most likely it's either '/' or '\'
 */
FX_WCHAR FX_GetFolderSeparator();

#ifndef _FXM_OPENSOURCE_
//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
/**
 * @brief	Create new folder.
 * @param[in] path	path name of folder.
 * @return	TRUE if success, or FALSE for error.
 */
FX_BOOL FX_CreateFolder(FX_LPCSTR path);
FX_BOOL FX_CreateFolder(FX_LPCWSTR path);
//<<<+++OPENSOURCE_END
#endif

//*****************************************************************************
//* File access
//*****************************************************************************
/** @brief File accessing handle. */
FX_DEFINEHANDLE(FX_HFILE)

#ifdef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_MUST_BEGIN LIC==GOOGLE
	#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
		#define FX_FILESIZE			FX_INT32
	#else
		#include <fcntl.h>
		#include <unistd.h>
		#include <sys/stat.h>

		#ifndef O_BINARY
			#define O_BINARY 		0
		#endif
		#ifndef O_LARGEFILE
			#define O_LARGEFILE		0
		#endif

		#define FX_FILESIZE			off_t
	#endif
	#define FX_GETBYTEOFFSET32(a)	0
	#define FX_GETBYTEOFFSET40(a)	0
	#define FX_GETBYTEOFFSET48(a)	0
	#define FX_GETBYTEOFFSET56(a)	0
	//<<<+++OPENSOURCE_MUST_END
#else
	//<<<+++OPENSOURCE_MUST_BEGIN LIC==FOXIT
	#if _FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN32_MOBILE_ || _FX_OS_ == _FX_WIN64_
		#if defined(_FX_LARGEFILE_SUPPORT_)
			/** @brief	Preprocessor for large file support. */
			#define _FX_LARGEFILE_USED_

			/** @brief	Support large file directly. */
			#define FX_FILESIZE		FX_INT64
			#define FX_GETBYTEOFFSET32(a)  ((FX_BYTE)(a>>32))
			#define FX_GETBYTEOFFSET40(a)  ((FX_BYTE)(a>>40))
			#define FX_GETBYTEOFFSET48(a)  ((FX_BYTE)(a>>48))
			#define FX_GETBYTEOFFSET56(a)  ((FX_BYTE)(a>>56))
		#else
			/** @brief	Only support 32-bit file size. */
			#define FX_FILESIZE		FX_INT32
			#define FX_GETBYTEOFFSET32(a)  0
			#define FX_GETBYTEOFFSET40(a)  0
			#define FX_GETBYTEOFFSET48(a)  0
			#define FX_GETBYTEOFFSET56(a)  0
		#endif
	#elif _FX_OS_ == _FX_LINUX_DESKTOP_ || _FX_OS_ == _FX_MACOSX_ || _FX_OS_ == _FX_IOS_ || _FX_OS_ == _FX_ANDROID_
		#if defined(_FX_LARGEFILE_SUPPORT_)
			/** @brief	Preprocessor for large file support. */
			#define _FX_LARGEFILE_USED_

			#ifndef _LARGEFILE_SOURCE
				#define _LARGEFILE_SOURCE
			#endif
			#ifndef _LARGEFILE64_SOURCE
				#define _LARGEFILE64_SOURCE
			#endif
		#endif
		#if defined(_FX_LARGEFILE_SUPPORT_)
			#define FX_GETBYTEOFFSET32(a)  ((FX_BYTE)(a>>32))
			#define FX_GETBYTEOFFSET40(a)  ((FX_BYTE)(a>>40))
			#define FX_GETBYTEOFFSET48(a)  ((FX_BYTE)(a>>48))
			#define FX_GETBYTEOFFSET56(a)  ((FX_BYTE)(a>>56))
		#else
			#define FX_GETBYTEOFFSET32(a)  0
			#define FX_GETBYTEOFFSET40(a)  0
			#define FX_GETBYTEOFFSET48(a)  0
			#define FX_GETBYTEOFFSET56(a)  0
		#endif
		#include <fcntl.h>
		#include <unistd.h>
		#include <sys/stat.h>

		#ifndef O_BINARY
			#define O_BINARY 	0
		#endif
		#ifndef O_LARGEFILE
			#define O_LARGEFILE 0
		#endif

		/** @brief	Use system-defined file size, 64-bit in Mac. */
		#define FX_FILESIZE		off_t
	#else //do not support large file.
		/** @brief	Only support 32-bit file size. */
		#define FX_FILESIZE		FX_INT32
		#define FX_GETBYTEOFFSET32(a)  0
		#define FX_GETBYTEOFFSET40(a)  0
		#define FX_GETBYTEOFFSET48(a)  0
		#define FX_GETBYTEOFFSET56(a)  0
	#endif
	//<<<+++OPENSOURCE_MUST_END
#endif
#define FX_GETBYTEOFFSET24(a)  ((FX_BYTE)(a>>24))
#define FX_GETBYTEOFFSET16(a)  ((FX_BYTE)(a>>16))
#define FX_GETBYTEOFFSET8(a)   ((FX_BYTE)(a>>8))
#define FX_GETBYTEOFFSET0(a)   ((FX_BYTE)(a))

/** @brief	File accessing modes. */
#define FX_FILEMODE_Write		0	//write mode, create automatically if the file doesn't exist.
#define FX_FILEMODE_ReadOnly	1	//read-only.
#define FX_FILEMODE_Truncate	2	//clear existing contents, size of file is to be 0, for writing mode only.

#ifndef _FXM_OPENSOURCE_
//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
/**
	* @brief	Open file with specified accessing mode.
	* @param[in] fileName	file path name to be opened.
	* @param[in] dwMode	file accessing mode, refer to FX_FILEMODE_XXX macros.
	* @return	File handler, NULL if fails.
	*/
FX_HFILE	FX_File_Open(FX_BSTR fileName, FX_DWORD dwMode, IFX_Allocator* pAllocator = NULL);
FX_HFILE	FX_File_Open(FX_WSTR fileName, FX_DWORD dwMode, IFX_Allocator* pAllocator = NULL);
/**
	* @brief	Close file.
	* @param[in] hFile		File handler returned by FX_File_Open.
	*/
void		FX_File_Close(FX_HFILE hFile, IFX_Allocator* pAllocator = NULL);
//<<<+++OPENSOURCE_END
#else
//<<<+++OPENSOURCE_BEGIN LIC==GOOGLE
FX_HFILE	FX_File_Open(FX_BSTR fileName, FX_DWORD dwMode);
FX_HFILE	FX_File_Open(FX_WSTR fileName, FX_DWORD dwMode);
void		FX_File_Close(FX_HFILE hFile);
//<<<+++OPENSOURCE_END
#endif

/**
 * @brief	Get file size.
 * @param[in] hFile		File handler returned by FX_File_Open.
 * @return	File size, 0 if file is empty or fails.
 */
FX_FILESIZE	FX_File_GetSize(FX_HFILE hFile);
/**
 * @brief	Get the current file accessing position.
 * @param[in] hFile		File handler returned by FX_File_Open.
 * @return	The current file accessing position from the beginning of file, -1 if fails.
 */
FX_FILESIZE	FX_File_GetPosition(FX_HFILE hFile);
/**
 * @brief	Set the current file accessing position.
 * @param[in] hFile		File handler returned by FX_File_Open.
 * @param[in] pos		The new accessing position.
 * @return	The current file accessing position from the beginning of file, -1 if fails.
 */
FX_FILESIZE	FX_File_SetPosition(FX_HFILE hFile, FX_FILESIZE pos);
/**
 * @brief	Read data from the current file accessing position.
 * @param[in] hFile		File handler returned by FX_File_Open.
 * @param[out] pBuffer	Buffer to receive data.
 * @param[in] szBuffer	Buffer size, in bytes.
 * @return	Returns the size of data read from file, 0 if there is no data or fails.
 */
size_t		FX_File_Read(FX_HFILE hFile, void* pBuffer, size_t szBuffer);
/**
 * @brief	Read data from specified position.
 * @param[in] hFile		File handler returned by FX_File_Open.
 * @param[out] pBuffer	Buffer to receive data.
 * @param[in] szBuffer	Buffer size, in bytes.
 * @param[in] pos		Position from which to read data, from the beginning of file.
 * @return	Returns the size of data read from file, 0 if there is no data or fails.
 */
size_t		FX_File_ReadPos(FX_HFILE hFile, void* pBuffer, size_t szBuffer, FX_FILESIZE pos);
/**
 * @brief	Write data from the current file accessing position.
 * @param[in] hFile		File handler returned by FX_File_Open.
 * @param[in] pBuffer	Buffer of data.
 * @param[in] szBuffer	Data size, in bytes.
 * @return	Returns the size of data write into file, < szBuffer fails.
 */
size_t		FX_File_Write(FX_HFILE hFile, const void* pBuffer, size_t szBuffer);
/**
 * @brief	Write data at specified position.
 * @param[in] hFile		File handler returned by FX_File_Open.
 * @param[in] pBuffer	Buffer of data.
 * @param[in] szBuffer	Data size, in bytes.
 * @param[in] pos		Position from which to write data, from the beginning of file.
 * @return	Returns the size of data write into file, < szBuffer fails.
 */
size_t		FX_File_WritePos(FX_HFILE hFile, const void* pBuffer, size_t szBuffer, FX_FILESIZE pos);
/**
 * @brief	Flush internal buffer if need.
 * @param[in] hFile		File handler returned by FX_File_Open.
 * @return	Returns FALSE if fails, or TRUE for success.
 */
FX_BOOL		FX_File_Flush(FX_HFILE hFile);
/**
 * @brief	Truncate file size.
 * @param[in] hFile		File handler returned by FX_File_Open.
 * @param[in] szFile	New file size.
 * @return	Returns FALSE if fails, or TRUE for success.
 */
FX_BOOL		FX_File_Truncate(FX_HFILE hFile, FX_FILESIZE szFile);

/**
 * @brief	Determine whether a file exists or not.
 * @param[in] fileName		File path name.
 * @return	Returns FALSE if there is no file, or TRUE if fileName exists.
 */
FX_BOOL		FX_File_Exist(FX_BSTR fileName);
FX_BOOL		FX_File_Exist(FX_WSTR fileName);
/**
 * @brief	Delete file.
 * @param[in] fileName		File path name.
 * @return	Returns FALSE if fails, or TRUE if succeeds.
 */
FX_BOOL		FX_File_Delete(FX_BSTR fileName);
FX_BOOL		FX_File_Delete(FX_WSTR fileName);
/**
 * @brief	Copy file.
 * @param[in] fileNameSrc	Source file path name.
 * @param[in] fileNameDst	Destination file path name.
 * @return	Returns FALSE if fails, or TRUE if succeeds.
 */
FX_BOOL		FX_File_Copy(FX_BSTR fileNameSrc, FX_BSTR fileNameDst);
FX_BOOL		FX_File_Copy(FX_WSTR fileNameSrc, FX_WSTR fileNameDst);
/**
 * @brief	Move file.
 * @param[in] fileNameSrc	Source file path name.
 * @param[in] fileNameDst	Destination file path name.
 * @return	Returns FALSE if fails, or TRUE if succeeds.
 */
FX_BOOL		FX_File_Move(FX_BSTR fileNameSrc, FX_BSTR fileNameDst);
FX_BOOL		FX_File_Move(FX_WSTR fileNameSrc, FX_WSTR fileNameDst);

//*****************************************************************************
//* IFX_StreamWrite/IFX_FileWrite
//*****************************************************************************
/** @brief stream writing interface. */
class IFX_StreamWrite
{
public:
	/** @brief	Called when to release everything */
	virtual void		Release() = 0;

	/**
	 * @brief	Write a block data. 
	 *
	 * @param[in] pData			The block data.
	 * @param[in] size			The length in bytes of the block data.
	 * @return	Return FALSE for failure;
	 */
	virtual	FX_BOOL		WriteBlock(const void* pData, size_t size) = 0;
};

/** @brief file writing interface. */
class IFX_FileWrite : public IFX_StreamWrite
{
public:
	/** @brief	Called when to release everything */
	virtual void			Release() = 0;

	/**
	 * @brief	Get total size of the file
	 *
	 * @return	File size, in bytes. Implementation can return 0 for any error.
	 */
	virtual FX_FILESIZE		GetSize() = 0;
	/**
	 * @brief	Flush internal buffer of the file
	 *
	 * @return	TRUE if flushes successfully, or FALSE to indicate error.
	 */
	virtual FX_BOOL			Flush() = 0;
	/**
	 * @brief	Write a block data. 
	 *
	 * @param[in] pData			The block data.
	 * @param[in] offset		Byte offset from beginning of the file
	 * @param[in] size			The length in bytes of the block data.
	 * @return	Return FALSE for failure;
	 */
	virtual	FX_BOOL			WriteBlock(const void* pData, FX_FILESIZE offset, size_t size) = 0;
	virtual	FX_BOOL			WriteBlock(const void* pData, size_t size) {return WriteBlock(pData, GetSize(), size);}
};
#ifndef _FXM_OPENSOURCE_
//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
/**
 * @brief	Create a CRT based file writing interface. Call Release() to destroy it. 
 *			Using MBCS file name. Available only for platforms supporting CRT file access (fopen, ...)
 * @return	An instance of IFX_FileWrite interface.
 */
IFX_FileWrite* FX_CreateFileWrite(FX_LPCSTR filename, IFX_Allocator* pAllocator = NULL);

/**
 * @brief	Create a CRT based file writing interface. Call Release() to destroy it. 
 *			Using unicode file name. Available only for platforms supporting CRT file access (fopen, ...)
 * @return	An instance of IFX_FileWrite interface.
 */
IFX_FileWrite* FX_CreateFileWrite(FX_LPCWSTR filename, IFX_Allocator* pAllocator = NULL);
//<<<+++OPENSOURCE_END
#else
//<<<+++OPENSOURCE_BEGIN LIC==GOOGLE
IFX_FileWrite* FX_CreateFileWrite(FX_LPCSTR filename);
IFX_FileWrite* FX_CreateFileWrite(FX_LPCWSTR filename);
//<<<+++OPENSOURCE_END
#endif

//*****************************************************************************
//* IFX_FileRead
//*****************************************************************************
/** @brief stream reading interface. */
class IFX_StreamRead
{
public:
	/** @brief	Called when to release everything */
	virtual void			Release() = 0;

	/** @brief	Determine whether reach the end of stream. */
	virtual FX_BOOL			IsEOF() = 0;
	/** @brief	Get the current reading position in stream. */
	virtual FX_FILESIZE		GetPosition() = 0;
	/**
	 * @brief	Read data block from sequential stream.
	 * @param[in,out] buffer	buffer to store data.
	 * @param[in] size			total size of buffer, in bytes.
	 * @return	The length of data stored in buffer. If returns 0, means error or no data.
	 */
	virtual size_t			ReadBlock(void* buffer, size_t size) = 0;
};

/** @brief file reading interface. */
class IFX_FileRead : IFX_StreamRead
{
public:
	/** @brief	Called when to release everything */
	virtual void			Release() = 0;

	/**
	 * @brief	Get total size of the file
	 * @return File size, in bytes. Implementation can return 0 for any error.
	 */
	virtual FX_FILESIZE		GetSize() = 0;
	/** @brief	Determine whether reach the end of stream. */
	virtual FX_BOOL			IsEOF() {return FALSE;}
	/** @brief	Get the current reading position in stream. */
	virtual FX_FILESIZE		GetPosition() {return 0;}
	/** @brief	Set accessing range. */
	virtual FX_BOOL			SetRange(FX_FILESIZE offset, FX_FILESIZE size) {return FALSE;}
	/** @brief	Clear accessing range set by SetRange method. */
	virtual void			ClearRange() {}

	/**
	 * @brief	Read a data block from the file
	 * @param[in,out] buffer	Pointer to a buffer receiving read data
	 * @param[in] offset		Byte offset from beginning of the file
	 * @param[in] size			Number of bytes for the block.
	 * @return TRUE for success, FALSE for failure.
	 */
	virtual FX_BOOL			ReadBlock(void* buffer, FX_FILESIZE offset, size_t size) = 0;
	/**
	 * @brief	Read data block from stream.
	 * @param[in,out] buffer	buffer to store data.
	 * @param[in] size			total size of buffer, in bytes.
	 * @return	The length of data stored in buffer. If returns 0, means error or no data.
	 */
	virtual size_t			ReadBlock(void* buffer, size_t size) {return 0;}
};
#ifndef _FXM_OPENSOURCE_
//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
/**
	* @brief	Create a CRT based file reading interface. Call Release() to destroy it. 
	*			Using MBCS file name. Available only for platforms supporting CRT file access
	* @return	An instance of IFX_FileWrite interface.
	*/
IFX_FileRead* FX_CreateFileRead(FX_LPCSTR filename, IFX_Allocator* pAllocator = NULL);

/**
	* @brief	Create a CRT based file reading interface. Call Release() to destroy it. 
	*			Using Unicode file name. Available only for platforms supporting CRT file access
	* @return	An instance of IFX_FileWrite interface.
	*/
IFX_FileRead* FX_CreateFileRead(FX_LPCWSTR filename, IFX_Allocator* pAllocator = NULL);
//<<<+++OPENSOURCE_END
#else
//<<<+++OPENSOURCE_BEGIN LIC==GOOGLE
IFX_FileRead* FX_CreateFileRead(FX_LPCSTR filename);
IFX_FileRead* FX_CreateFileRead(FX_LPCWSTR filename);
//<<<+++OPENSOURCE_END
#endif

//*****************************************************************************
//* IFX_FileStream
//*****************************************************************************
/** @brief	File stream interface, reading & writing. */
class IFX_FileStream : public IFX_FileRead, public IFX_FileWrite
{
public:
	/** @brief	Create a shared instance. */
	virtual IFX_FileStream*		Retain() = 0;
	/** @brief	Destroy the current instance. */
	virtual void				Release() = 0;

	/** @brief	Get the current stream size, in bytes. */
	virtual FX_FILESIZE			GetSize() = 0;
	/** @brief	Determine whether reach the end of stream. */
	virtual FX_BOOL				IsEOF() = 0;
	/** @brief	Get the current reading position in stream. */
	virtual FX_FILESIZE			GetPosition() = 0;

	/**
	 * @brief	Read a data block from stream
	 * @param[in,out] buffer	Pointer to a buffer receiving data
	 * @param[in] offset		Byte offset from beginning of the file, the position to read data
	 * @param[in] size			Number of bytes to be read from stream
	 * @return TRUE for success, FALSE for failure.
	 */
	virtual FX_BOOL				ReadBlock(void* buffer, FX_FILESIZE offset, size_t size) = 0;
	/**
	 * @brief	Read data block from stream.
	 * @param[in,out] buffer	buffer to store data.
	 * @param[in] size			total size of buffer, in bytes.
	 * @return	The length of data stored in buffer. If returns 0, means error or no data.
	 */
	virtual size_t				ReadBlock(void* buffer, size_t size) = 0;

	/**
	 * @brief	Write a block data into stream. 
	 * @param[in] buffer		Pointer to the data block.
	 * @param[in] offset		Byte offset from beginning of the file, the position to write data.
	 * @param[in] size			The length in bytes of the buffer.
	 * @return Return FALSE for failure;
	 */
	virtual	FX_BOOL				WriteBlock(const void* buffer, FX_FILESIZE offset, size_t size) = 0;
	virtual	FX_BOOL				WriteBlock(const void* buffer, size_t size) {return WriteBlock(buffer, GetSize(), size);}

	/**
	 * @brief	Flush internal buffer
	 * @return	TRUE if flushes successfully, or FALSE to indicate error.
	 */
	virtual FX_BOOL				Flush() = 0;
};
#ifndef _FXM_OPENSOURCE_
//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
/**
 * @brief	Create a CRT based file I/O interface. Call Release() to destroy it. 
 *			Using MBCS file name. Available only for platforms supporting CRT file access.
 * @return	An instance of IFX_FileStream interface, NULL if fails.
 */
IFX_FileStream*		FX_CreateFileStream(FX_LPCSTR filename, FX_DWORD dwModes, IFX_Allocator* pAllocator = NULL);

/**
 * @brief	Create a CRT based file I/O interface. Call Release() to destroy it. 
 *			Using Unicode file name. Available only for platforms supporting CRT file access.
 * @return	An instance of IFX_FileStream interface, NULL if fails.
 */
IFX_FileStream*		FX_CreateFileStream(FX_LPCWSTR filename, FX_DWORD dwModes, IFX_Allocator* pAllocator = NULL);
//<<<+++OPENSOURCE_END
#else
//<<<+++OPENSOURCE_BEGIN LIC==GOOGLE
IFX_FileStream*		FX_CreateFileStream(FX_LPCSTR filename, FX_DWORD dwModes);
IFX_FileStream*		FX_CreateFileStream(FX_LPCWSTR filename, FX_DWORD dwModes);
//<<<+++OPENSOURCE_END
#endif
#ifndef _FXM_OPENSOURCE_
//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
//*****************************************************************************
//* IFX_FileAccess
//*****************************************************************************
/** @brief	File access interface, open file. */
class IFX_FileAccess
{
public:
	/** @brief	Destroy the current instance. */
	virtual void				Release() = 0;
	
	virtual IFX_FileAccess*		Retain() = 0;
	/** 
	 * @brief	Get current path string 
	 * @param[out] wsPath		get current file path.
	 */
	virtual void				GetPath(CFX_WideString& wsPath) = 0;

	/** 
	 * @brief	Creat IFX_FileStream to operate file.
	 * @param[in] dwModes		open file mode.
	 */
	virtual IFX_FileStream*		CreateFileStream(FX_DWORD dwModes) = 0;
};

/**
 * @brief	Create a CRT based file I/O interface. Call Release() to destroy it. 
 *			
 * @return	An instance of IFX_FileAccess interface, NULL if fails.
 */
IFX_FileAccess*		FX_CreateDefaultFileAccess(FX_WSTR  wsPath, IFX_Allocator* pAllocator = NULL);

class IFX_FileCollection
{
public:
	virtual void				Release() = 0;

	virtual FX_POSITION			GetStartPos() = 0;
	virtual IFX_FileAccess*		GetNextFile(FX_POSITION& pos) = 0;
};
//<<<+++OPENSOURCE_END
#endif
//*****************************************************************************
//* Memory stream
//*****************************************************************************
/** @brief Memory stream interface. */
class IFX_MemoryStream : public IFX_FileStream
{
public:
	/**
	 * @brief	Determine the current mode is consecutive or not.
	 * @return	TRUE if it's consecutive, or FALSE if it's non-consecutive.
	 */
	virtual FX_BOOL			IsConsecutive() const = 0;
	/**
	 * @brief	Change initialize size and grow size.
	 * @param[in] nInitSize		Initial size for memory block.
	 * @param[in] nGrowSize		Grow up size for next change when write data.
	 * @remark	For consecutive mode, if nInitSize is greater than the current size, block memory will be reallocated;
	 *			nGrowSize will be used when reallocate memory next time.
	 *			For non-consecutive mode, nGrowSize will be used to allocate each memory block, this method should be called at first;
	 *			nInitSize will be ignored.
	 */
	virtual void			EstimateSize(size_t nInitSize, size_t nGrowSize) = 0;
	/**
	 * @brief	Get the current memory buffer.
	 * @return	The current memory buffer.
	 * @remark	If the current memory stream works under non-consecutive mode(there are more than one memory blocks),
	 *			only the first block returns.
	 */
	virtual FX_LPBYTE		GetBuffer() const = 0;
	/**
	 * @brief	Attach a memory buffer.
	 * @param[in] pBuffer	Memory buffer to attach.
	 * @param[in] nSize		Buffer size, in bytes.
	 * @param[in] bTakeOver	Indicates whether need free attached memory buffer(pBuffer) when memory stream is to be released.
	 * @remark	This method will let memory stream works under consecutive mode, that's only one block exists,
	 *			it will be expanded when writes data into it if necessary.
	 *			If memory stream works under non-consecutive mode, this method makes no sense.
	 */
	virtual void			AttachBuffer(FX_LPBYTE pBuffer, size_t nSize, FX_BOOL bTakeOver = FALSE) = 0;
	/**
	 * @brief	Detach the current memory buffer.
	 * @remark	If memory stream works under non-consecutive mode, this method makes no sense.
	 */
	virtual void			DetachBuffer() = 0;
};
#ifndef _FXM_OPENSOURCE_
//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
/**
	* @brief	Creates a stream object by a given memory buffer.
	*			This function creates a consecutive memory stream object.
	* @param[in] pBuffer		a memory buffer to read/write data.
	* @param[in] nSize			buffer size, in bytes.
	* @param[in] bTakeOver		indicates whether need take over pBuffer, if it's TRUE, pBuffer will release internally
	*							when destroy returned IFX_MemoryStream object.
	* @param[in] pAllocator	Pointer to ::IFX_Allocator object, this specifies an allocator. If it's NULL, default allocator is used.
	* @return	An instance of IFX_MemoryStream interface, NULL if fails.
	*/
IFX_MemoryStream*	FX_CreateMemoryStream(FX_LPBYTE pBuffer, size_t nSize, FX_BOOL bTakeOver = FALSE, IFX_Allocator* pAllocator = NULL);

/**
	* @brief	Create a memory stream object.
	*			Memory buffer will be created internally, and the size will increase when need more space.
	* @param[in] bConsecutive	Indicates to create a consecutive memory stream if it's TRUE, non-consecutive one if it's FALSE.
	* @param[in] pAllocator	Pointer to ::IFX_Allocator object, this specifies an allocator. If it's NULL, default allocator is used.
	* @return	An instance of IFX_MemoryStream interface, NULL if fails.
	*/
IFX_MemoryStream*	FX_CreateMemoryStream(FX_BOOL bConsecutive = FALSE, IFX_Allocator* pAllocator = NULL);
//<<<+++OPENSOURCE_END
#else
//<<<+++OPENSOURCE_BEGIN LIC==GOOGLE
IFX_MemoryStream*	FX_CreateMemoryStream(FX_LPBYTE pBuffer, size_t nSize, FX_BOOL bTakeOver = FALSE);
IFX_MemoryStream*	FX_CreateMemoryStream(FX_BOOL bConsecutive = FALSE);
//<<<+++OPENSOURCE_END
#endif
//*****************************************************************************
//* Buffer read stream
//*****************************************************************************
/**
 * @brief	IFX_BufferRead stream provides an optimized approach to read stream data.
 *			Usually, one stream maintains an internal buffer for data access, this buffer
 *			can be used directly to caller, and avoids data-copy.
 */
class IFX_BufferRead : public IFX_StreamRead
{
public:
	/** Called when to release the current instance. */
	virtual void			Release() = 0;

	/** Determine whether reach the end of stream. */
	virtual FX_BOOL			IsEOF() = 0;
	/** Get the current reading position in stream. */
	virtual FX_FILESIZE		GetPosition() = 0;

	/**
	 * @brief	Read data block from sequential stream.
	 * @param[in,out] buffer	buffer to store data.
	 * @param[in] size			total size of buffer, in bytes.
	 * @return	The length of data stored in buffer. If returns 0, means error or no data.
	 */
	virtual size_t			ReadBlock(void* buffer, size_t size) = 0;

	/**
	 * @brief	Read the next block in sequential stream.
	 * @param[in] bRestart	Indicates to read data from the beginning of stream.
	 * @return	If no error, returns TRUE, or FALSE.
	 */
	virtual FX_BOOL			ReadNextBlock(FX_BOOL bRestart = FALSE) = 0;
	/** Get internal buffer of block data. */
	virtual FX_LPCBYTE		GetBlockBuffer() = 0;
	/** Get the size of data in internal buffer. */
	virtual size_t			GetBlockSize() = 0;
	/** Get the offset of data in internal buffer. This offset starts from the beginning of stream. */
	virtual FX_FILESIZE		GetBlockOffset() = 0;
};

#ifndef _FXM_OPENSOURCE_
//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
//*****************************************************************************
//* Cached file read
//*****************************************************************************
#define FX_FILECACHE_CHUNKSIZE  32768
#define FX_FILECACHE_CHUNKCOUNT	64

/** @brief Cached file read interface. */
class CFX_CachedFileRead : public IFX_FileStream, public CFX_Object
{
public:
	CFX_CachedFileRead();
	virtual	~CFX_CachedFileRead();

			/**
			 * @brief	Initialize the chunk size and chunk count.
			 * @param[in] nChunkSize	The size of each chunk.
			 * @param[in] nChunkCount	The total count of chunks.
			 * @param[in] pBuffer		External buffer, if NULL, cache is disabled.
			 * @param[in] pAllocator	Allocator used in this class. NULL to use default allocator.
			 * @return	None.
			*/
			FX_BOOL			Init(FX_INT32 nChunkSize, FX_INT32 nChunkCount, FX_LPVOID pBuffer, IFX_Allocator* pAllocator = NULL);
			/**
			 * @brief	Attach a file read.
			 * @param[in] pFile				The file to be attached.
			 * @param[in] bTakeOver			Take over the file or not.
			 * @return	None.
			*/
			FX_BOOL			AttachFile(IFX_FileRead* pFile, FX_BOOL bTakeOver);
			/**
			 * @brief	Attach a file read.
			 * @param[in] offset			The file to be attached.
			 * @param[in] nCacheCount		Take over the file or not.
			 * @return	None.
			*/
			FX_BOOL			PreCache(FX_FILESIZE offset, FX_INT32 nCacheCount);

	/**
	 * @brief	Get total size of the file
	 * @return File size, in bytes. Implementation can return 0 for any error.
	 */
	virtual FX_FILESIZE		GetSize();
	/** @brief	Determine whether reach the end of stream. */
	virtual FX_BOOL			IsEOF();
	/** @brief	Get the current reading position in stream. */
	virtual FX_FILESIZE		GetPosition();

	/**
	 * @brief	Read a data block from the file
	 * @param[in,out] buffer	Pointer to a buffer receiving read data
	 * @param[in] offset		Byte offset from beginning of the file
	 * @param[in] size			Number of bytes for the block.
	 * @return TRUE for success, FALSE for failure.
	 */
	virtual FX_BOOL			ReadBlock(void* buffer, FX_FILESIZE offset, size_t size);
	/**
	 * @brief	Read data block from stream.
	 * @param[in,out] buffer	buffer to store data.
	 * @param[in] size			total size of buffer, in bytes.
	 * @return	The length of data stored in buffer. If returns 0, means error or no data.
	 */
	virtual size_t			ReadBlock(void* buffer, size_t size);

protected:
	FXMT_LOCKOBJECT_DEFINE(m_LockObj);
	FX_LPVOID				m_pData;
	FX_DWORD				m_dwCount;

	/** @brief	Create a shared instance. */
	virtual IFX_FileStream*	Retain();
	/** @brief	Called when to release everything */
	virtual void			Release();
	/** @brief	Write a block data into stream. Unsupported for reading mode, return FALSE directly. */
	virtual	FX_BOOL			WriteBlock(const void* buffer, FX_FILESIZE offset, size_t size) {return FALSE;}
	/** @brief	Flush internal buffer. Unsupported for reading mode, return FALSE directly. */
	virtual FX_BOOL			Flush() {return FALSE;}
};
//<<<+++OPENSOURCE_END
#endif

//<<<+++OPENSOURCE_MUST_BEGIN
#endif // _FX_STREAM_H_
//<<<+++OPENSOURCE_MUST_END

/** @} */

//<<<+++OPENSOURCE_END
